﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace CCL.SocketMessage.Request
{
    /// <summary>
    /// 파일 업로드를 요청하는 Message의 Body를 제공합니다.
    /// </summary>
    public class FileUpload : Body
    {
        /// <summary>
        /// Project 고유 ID를 가져옵니다.
        /// </summary>
        public int ProjectID { get; private set; }

        /// <summary>
        /// 업로드 하고자 하는 Revision을 가져옵니다.
        /// </summary>
        public int Revision { get; private set; }

        /// <summary>
        /// 상대경로의 글자길이를 가져옵니다.
        /// </summary>
        public int RelativePathLength { get; private set; }

        /// <summary>
        /// 프로젝트의 루트로부터의 상대경로를 가져옵니다. (파일이름포함)
        /// </summary>
        public string RelativePath { get; private set; }

        /// <summary>
        /// 전송하려는 파일의 크기를 가져옵니다.
        /// </summary>
        public int FileSize { get; private set; }

        /// <summary>
        /// 전송하려는 파일의 바이트 배열을 가져옵니다.
        /// </summary>
        public byte[] FileBytes { get; private set; }

        /// <summary>
        /// 새로운 FileUpload 객체를 생성합니다.
        /// </summary>
        /// <param name="projId">Project 고유 ID</param>
        /// <param name="revision">Commit Revision</param>
        /// <param name="relativePath">프로젝트 루트로부터 상대경로</param>
        /// <param name="absolutePath">절대경로</param>
        public FileUpload(int projId, int revision, string relativePath, string absolutePath)
        {
            ProjectID = projId;
            Revision = revision;

            RelativePath = relativePath;
            RelativePathLength = relativePath.Length;

            using (FileStream fs = new FileStream(absolutePath, FileMode.Open, FileAccess.Read))
            {
                FileSize = Convert.ToInt32(fs.Length);
                BinaryReader br = new BinaryReader(fs);
                FileBytes = br.ReadBytes(FileSize);

                br.Dispose();
            }
        }

        /// <summary>
        /// 직렬화된 byte 배열을 통해 FileUpload 객체를 생성합니다.
        /// </summary>
        /// <param name="bytes">직렬화된 byte 배열</param></param>
        public FileUpload(byte[] bytes)
        {
            int start = 0;

            ProjectID = BitConverter.ToInt32(bytes, start);
            start += sizeof(Int32);

            Revision = BitConverter.ToInt32(bytes, start);
            start += sizeof(Int32);

            RelativePathLength = BitConverter.ToInt32(bytes, start);
            start += sizeof(Int32);

            RelativePath = Encoding.Default.GetString(bytes, start, RelativePathLength);
            start += RelativePathLength;

            FileSize = BitConverter.ToInt32(bytes, start);
            start += sizeof(Int32);
            
            FileBytes = new byte[FileSize];
            Array.Copy(bytes, start, FileBytes, 0, FileSize);
            start += FileBytes.Length;
        }

        /// <summary>
        /// 바이트 배열로 직렬화 합니다.
        /// </summary>
        /// <returns>직렬화된 바이트 배열</returns>
        public override byte[] GetByte()
        {
            byte[] bytes = new byte[GetSize()];

            byte[] temp;
            int start = 0;

            temp = BitConverter.GetBytes(ProjectID);
            Array.Copy(temp, 0, bytes, start, temp.Length);
            start += temp.Length;

            temp = BitConverter.GetBytes(Revision);
            Array.Copy(temp, 0, bytes, start, temp.Length);
            start += temp.Length;

            temp = BitConverter.GetBytes(RelativePathLength);
            Array.Copy(temp, 0, bytes, start, temp.Length);
            start += temp.Length;

            temp = Utility.StringUtility.StringToBytes(RelativePath, RelativePathLength);
            Array.Copy(temp, 0, bytes, start, temp.Length);
            start += temp.Length;

            temp = BitConverter.GetBytes(FileSize);
            Array.Copy(temp, 0, bytes, start, temp.Length);
            start += temp.Length;

            temp = FileBytes;
            Array.Copy(temp, 0, bytes, start, temp.Length);
            start += temp.Length;

            return bytes;
        }

        /// <summary>
        /// 직렬화 가능한 객체의 바이트 사이즈를 가져옵니다.
        /// </summary>
        /// <returns>직렬화된 바이트 사이즈</returns>
        public override uint GetSize()
        {
            uint size = 0;

            size += sizeof(int);                    // ProjectID
            size += sizeof(int);                    // Revision
            size += sizeof(int);                    // RelativePathLength
            size += (uint)RelativePathLength;             // RelativePath
            size += sizeof(int);                    // FileSize
            size += (uint)FileBytes.Length;         // FileBytes

            return size;
        }
    }
}
